import subprocess
import sys
import webbrowser

from PyQt5 import QtWebSockets
from PyQt5.QtWidgets import (
    QWidget,
    QGridLayout,
    QPushButton,
    QApplication,
    QLineEdit,
    QLabel,

    QFileDialog,
    QHBoxLayout,
    QComboBox,
    QCheckBox,
    QButtonGroup, QSplitter, QVBoxLayout, QTextEdit, QFormLayout, QSizePolicy, QMainWindow, QAction, QMenu, QMenuBar,
    QFrame,
)
from PyQt5.QtCore import Qt, pyqtSignal, QObject, QThread, QCoreApplication, QUrl
from PyQt5.QtGui import QIcon, QTextCursor, QImage, QPixmap, QFont
from PyQt5.QtWebSockets import QWebSocket, QWebSocketProtocol

import base64
import io
# from PIL import Image
from slide_func_v2 import *
import os
import json
from queue import Queue
import warnings

warnings.filterwarnings("ignore", category=RuntimeWarning)


class RedirectText(QObject):
    write_signal = pyqtSignal(str)

    def __init__(self, parent=None):
        super().__init__(parent)

    def write(self, text):
        self.write_signal.emit(text)


class MainUi(QWidget):
    def __init__(self):
        super().__init__()
        if getattr(sys, 'frozen', False):
            # 当运行打包后的可执行文件时
            self.conf_dir = os.path.join(sys._MEIPASS, "conf")  # type: ignore
        else:
            # 在开发环境中
            self.conf_dir = os.path.join(os.path.dirname(__file__), "conf")

        self.ques_mark = b"iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAdhJREFUWEfFV9txwzAMk/fhDmkmazNZ3R20T3v0kT6IoSTI/qg/ktiRSBB8GNrKwiUiH6WUT9ii93rt9v2j37XWL9bsxiwUke9SijtjtuiaFwNkCEBENBKM2J03EdvDRwfkEEgXQBK1OlVj7jxlwkDrfwh8r7U+sw1vACzPSjlGO3UcjZudWDPPGEAG4BeMUXkcFUVMY6218dncBNpvO3dgAUSTjhNAWDR1DhSfBIyqvmcfATj1Q+cwC3pt+ZZnYOJsZ0/FAWAl+kinGUcw3YoPBX6scwBU9AD2Edsq1A/NwrYS/aTalQVv3xGAZl0DILYIO3OTNHYB2FpnfFcAXhjd3DFARGQljadPBDBtvR4QNv9JNxwM0MgzAKvOY7puAQgFPMw7gsd9t2rgKnsA4HoRhqFCR28pSItQpRSlkMwI1fedujnrTlNw2RDTnolOQJX1iqP41ixgAGEBKuMOAEUnnU9oQWqGZGM/ex1TLETpxtRPjF4ZuyxIwkCZMjAVJKE99HZq1LuBVMquknNJBnP6/0Rp0t8HE/rBnHLCuHVJjmppLssz/WbPKCAdzcgfTHovjdDjejo6DqJ26bFMr0yoXjuakUBGs4dqZ3r2Q9vpzxgxnheXjnF/hRdbUR7UojcAAAAASUVORK5CYII="
        self.config_path = os.path.join(self.conf_dir, "fb_params.conf")
        self.config_ini_path = os.path.join(self.conf_dir, "fb_params _ini.conf")
        print(self.config_ini_path)
        # self.chanloc_bp = os.path.join(self.conf_dir, "chanlocs_bp32.mat")
        self.chanloc_bp = os.path.join(self.conf_dir, "chanlocs_bp32.mat")
        self.chanloc_edf = os.path.join(self.conf_dir, "chanlocs_edf.mat")
        # self.chanloc_path = os.path.join(self.conf_dir, "chanlocs_bp32.mat")
        self.chanloc_path = ''
        self.calc_mode = "fb_EEG_network"
        self.vhdr_path = ''
        self.save_path = ''
        self.help_path = os.path.join(self.conf_dir, "NeuroCut帮助文档.pdf")
        self.gender = "male"
        self.baseflag = "0"
        self.datalen_txt = "5"
        self.webSocket = QWebSocket()
        self.webSocket.connected.connect(self.websocketConnect)
        self.webSocket.disconnected.connect(self.webSocketDisconnect)
        self.webSocket.textMessageReceived.connect(self.webSocketMessageReceived)
        self.initUI()

        #线程
        self.test_thread = None  # 定义test_thread属性
        self.lock = threading.Lock()  # 类级别的锁，用于确保同时只有一个线程可以执行start_test

    def initUI(self):
        main_layout = QVBoxLayout()  # 最外层主容器（垂直）（func_layout + run end）

        func_layout = QHBoxLayout()  # 上层容器（水平）：grid+日志

        grid = QGridLayout()  #上左侧参数容器(三个路径+参数+图片)

        grid1 = QHBoxLayout()  # 水平(grid2+图片显示)
        grid2 = QGridLayout()  #垂直（参数+FTP）
        grid3 = QGridLayout()  #垂直（图片+文字）
        # 数据路径
        self.data_label = QLabel("数据路径:")
        # self.data_label.setFixedWidth(50)
        self.data_txt = QLineEdit()
        # self.data_txt.setFixedWidth(200)
        self.data_txt.setPlaceholderText("请选择数据文件")
        self.data_txt.setReadOnly(True)
        self.data_btn = QPushButton("浏览")
        # self.data_btn.setFixedWidth(80)
        self.data_btn.clicked.connect(self.select_vhdr)
        self.data_label_img = QLabel()
        self.data_label_img.setFixedWidth(18)
        self.data_label_img.setFixedHeight(18)
        self.set_img_on_label(self.data_label_img, self.ques_mark)
        self.data_label_img.setToolTip("导入的数据应为BP设备采集的 .vhdr格式的数据")

        self.hbox_data = QHBoxLayout()
        self.hbox_data.addWidget(self.data_label)
        self.hbox_data.addWidget(self.data_txt)
        self.hbox_data.addWidget(self.data_btn)
        self.hbox_data.addWidget(self.data_label_img)
        # self.hbox1.setAlignment(Qt.AlignLeft)
        grid.addLayout(self.hbox_data, 0, 0)

        # 保存路径
        self.save_label = QLabel("保存路径:")
        self.save_txt = QLineEdit()
        self.save_txt.setPlaceholderText("请选择保存路径")
        self.save_txt.setReadOnly(True)
        self.save_btn = QPushButton("浏览")
        self.save_btn.clicked.connect(self.select_save_dir)
        self.save_label_img = QLabel()
        self.save_label_img.setFixedWidth(18)
        self.save_label_img.setFixedHeight(18)
        self.set_img_on_label(self.save_label_img, self.ques_mark)
        self.save_label_img.setToolTip("剪切的数据段存储路径")

        self.hbox_save = QHBoxLayout()
        self.hbox_save.addWidget(self.save_label)
        self.hbox_save.addWidget(self.save_txt)
        self.hbox_save.addWidget(self.save_btn)
        self.hbox_save.addWidget(self.save_label_img)
        grid.addLayout(self.hbox_save, 1, 0)

        # 导联路径
        self.channel_label = QLabel("导联路径:")
        self.channel_txt = QLineEdit()
        self.channel_txt.setPlaceholderText("默认")
        self.channel_txt.setReadOnly(True)
        self.channel_btn = QPushButton("浏览")
        self.channel_btn.clicked.connect(self.select_channel)
        self.channel_label_img = QLabel()
        self.channel_label_img.setFixedWidth(18)
        self.channel_label_img.setFixedHeight(18)
        self.set_img_on_label(self.channel_label_img, self.ques_mark)
        self.channel_label_img.setToolTip(
            "数据的导联坐标文件的路径，默认为BP设备的坐标文件AS_32_REF.bvef的坐标文件（chanlocs_v3.mat）")

        self.hbox_chan = QHBoxLayout()
        self.hbox_chan.addWidget(self.channel_label)
        self.hbox_chan.addWidget(self.channel_txt)
        self.hbox_chan.addWidget(self.channel_btn)
        self.hbox_chan.addWidget(self.channel_label_img)
        grid.addLayout(self.hbox_chan, 2, 0)

        # 在布局中插入空白的QWidget来设置间距
        spacer1 = QWidget()
        spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        grid.addWidget(spacer1, 3, 0)

        # 参数设置
        self.paramode = QVBoxLayout()

        self.paras_label = QLabel("[ 参数设置 ]")
        self.hbox_paras = QHBoxLayout()
        self.hbox_paras.addWidget(self.paras_label, Qt.AlignLeft)
        self.paramode.addLayout(self.hbox_paras, 1)

        # 计算参数
        self.parameters_label = QLabel("计算参数:")
        self.parameters_label.setFixedWidth(50)
        # 实例化QComBox对象
        self.select_params_module = QComboBox(self)
        self.select_params_module.setFixedWidth(120)
        self.select_params_module.addItems(["默认配置文件", "修改配置文件", "导入配置文件"])

        self.params_label_img = QLabel()
        self.params_label_img.setFixedWidth(18)
        self.params_label_img.setFixedHeight(18)
        self.set_img_on_label(self.params_label_img, self.ques_mark)
        self.params_label_img.setToolTip(
            "默认配置文件：初始化参数配置文件 \n修改配置文件：手动修改fb_params.conf文件中的内容 \n导入配置文件：手动导入fb_params.conf文件"
        )

        self.hbox_parameters = QHBoxLayout()
        self.hbox_parameters.addWidget(self.parameters_label)
        self.hbox_parameters.addWidget(self.select_params_module)
        self.hbox_parameters.addWidget(self.params_label_img)
        self.hbox_parameters.setAlignment(Qt.AlignLeft)
        self.paramode.addLayout(self.hbox_parameters, 2)

        # 创建复选框，标记状态改变时信号触发事件
        self.model_label = QLabel("计算模式:")
        self.model_label.setFixedWidth(50)
        self.power_checkbox = QCheckBox("Power")

        self.power_checkbox.toggled.connect(self.change_calc_mode)

        self.network_checkbox = QCheckBox("Network")
        self.network_checkbox.setChecked(True)
        self.network_checkbox.toggled.connect(self.change_calc_mode)

        # self.power_checkbox.setVisible(False)
        # self.network_checkbox.setVisible(False)

        self.calc_gp = QButtonGroup(self)
        # Exclusive属性设置为True时，一组按钮中只有一个按钮可以被选中
        self.calc_gp.setExclusive(True)
        self.calc_gp.addButton(self.power_checkbox)
        self.calc_gp.addButton(self.network_checkbox)

        self.modle_label_img = QLabel()
        self.modle_label_img.setFixedWidth(18)
        self.modle_label_img.setFixedHeight(18)
        self.set_img_on_label(self.modle_label_img, self.ques_mark)
        self.modle_label_img.setToolTip(
            "计算模式：选择反馈指标模式，power和network（默认为network）"
        )

        self.hbox_modle = QHBoxLayout()
        self.hbox_modle.addWidget(self.model_label)
        self.hbox_modle.addWidget(self.power_checkbox)
        self.hbox_modle.addWidget(self.network_checkbox)
        self.hbox_modle.addWidget(self.modle_label_img)
        self.paramode.addLayout(self.hbox_modle, 3)
        self.select_params_module.currentIndexChanged[str].connect(self.select_item)

        # name
        self.sub_id = QLabel("ID:")
        self.sub_id.setFixedWidth(50)
        self.sub_id_txt = QLineEdit()
        self.sub_id_txt.setFixedWidth(120)
        self.subinfo_label_img = QLabel()
        self.subinfo_label_img.setFixedWidth(18)
        self.subinfo_label_img.setFixedHeight(18)
        self.set_img_on_label(self.subinfo_label_img, self.ques_mark)
        self.subinfo_label_img.setToolTip(
            "ID：被试id。例如：sub001 ")
        self.hboxid = QHBoxLayout()
        self.hboxid.addWidget(self.sub_id)
        self.hboxid.addWidget(self.sub_id_txt)
        self.hboxid.addWidget(self.subinfo_label_img)
        self.hboxid.setAlignment(Qt.AlignLeft)
        self.paramode.addLayout(self.hboxid, 4)
        # name
        self.sub_name = QLabel("姓名:")
        self.sub_name.setFixedWidth(50)
        self.sub_name_txt = QLineEdit()
        self.sub_name_txt.setFixedWidth(120)
        self.subinfo_label_img = QLabel()
        self.subinfo_label_img.setFixedWidth(18)
        self.subinfo_label_img.setFixedHeight(18)
        self.set_img_on_label(self.subinfo_label_img, self.ques_mark)
        self.subinfo_label_img.setToolTip(
            "姓名：被试姓名（全拼或缩写）。默认为 fb")
        self.hbox_name = QHBoxLayout()
        # self.hbox44.addWidget(self.sub_name, Qt.AlignLeft)
        #self.hbox44.addSpacing(20)  # 添加间距
        # self.hbox44.addWidget(self.sub_name_txt, 90, Qt.AlignLeft)
        # self.hbox44.addWidget(self.subinfo_label_img, 0, Qt.AlignLeft)
        self.hbox_name.addWidget(self.sub_name)
        self.hbox_name.addWidget(self.sub_name_txt)
        self.hbox_name.addWidget(self.subinfo_label_img)
        self.hbox_name.setAlignment(Qt.AlignLeft)
        self.paramode.addLayout(self.hbox_name, 5)
        #age
        self.sub_age = QLabel("年龄:")
        self.sub_age.setFixedWidth(50)
        self.sub_age_txt = QLineEdit()
        self.sub_age_txt.setFixedWidth(120)
        # self.subinfo_btn = QPushButton("确定")
        # self.subinfo_btn.setFixedWidth(80)
        # self.subinfo_btn.clicked.connect(self.change_age)
        self.subinfo_label_img = QLabel()
        self.subinfo_label_img.setFixedWidth(18)
        self.subinfo_label_img.setFixedHeight(18)
        self.set_img_on_label(self.subinfo_label_img, self.ques_mark)
        self.subinfo_label_img.setToolTip(
            "年龄：被试年龄。默认为 []")
        self.hbox_age = QHBoxLayout()
        self.hbox_age.addWidget(self.sub_age)
        self.hbox_age.addWidget(self.sub_age_txt)
        self.hbox_age.addWidget(self.subinfo_label_img)
        # self.hbox_age.addWidget(self.subinfo_btn)
        self.hbox_age.setAlignment(Qt.AlignLeft)
        self.paramode.addLayout(self.hbox_age, 6)

        #性别
        self.sub_gender = QLabel("性别:")
        self.sub_gender.setFixedWidth(50)
        # 创建复选框，标记状态改变时信号触发事件
        self.male_checkbox = QCheckBox("男")
        self.male_checkbox.setChecked(True)
        self.male_checkbox.toggled.connect(self.change_gender)
        self.female_checkbox = QCheckBox("女")
        self.female_checkbox.toggled.connect(self.change_gender)

        self.male_checkbox.setVisible(True)
        self.female_checkbox.setVisible(True)

        self.gender_gp = QButtonGroup(self)
        # Exclusive属性设置为True时，一组按钮中只有一个按钮可以被选中
        self.gender_gp.setExclusive(True)
        self.gender_gp.addButton(self.male_checkbox)
        self.gender_gp.addButton(self.female_checkbox)

        self.hbox_gender = QHBoxLayout()
        self.hbox_gender.addWidget(self.sub_gender, Qt.AlignLeft)
        self.hbox_gender.addWidget(self.male_checkbox, Qt.AlignLeft)
        self.hbox_gender.addWidget(self.female_checkbox, Qt.AlignLeft)
        self.paramode.addLayout(self.hbox_gender, 7)
        # self.select_params_module.currentIndexChanged[str].connect(self.select_item)

        #空白
        spacer1 = QWidget()
        spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.paramode.addWidget(spacer1, 8)

        #基线base block and upregulation blocks
        # self.paradigm = QLabel("模式:")
        # self.paradigm.setFixedWidth(50)
        # # 创建复选框，标记状态改变时信号触发事件
        # self.base_checkbox = QCheckBox("基线")
        # # self.base_checkbox.setChecked(True)
        # self.base_checkbox.toggled.connect(self.change_paradigm)
        # self.upregulation_checkbox = QCheckBox("反馈")
        # self.upregulation_checkbox.setChecked(True)
        # self.upregulation_checkbox.toggled.connect(self.change_paradigm)
        # #设置为可见状态
        # self.base_checkbox.setVisible(True)
        # self.upregulation_checkbox.setVisible(True)

        # self.paradigm_gp = QButtonGroup(self)
        # # Exclusive属性设置为True时，一组按钮中只有一个按钮可以被选中
        # self.paradigm_gp.setExclusive(True)
        # self.paradigm_gp.addButton(self.base_checkbox)
        # self.paradigm_gp.addButton(self.upregulation_checkbox)
        #
        # self.subinfo_label_img = QLabel()
        # self.subinfo_label_img.setFixedWidth(18)
        # self.subinfo_label_img.setFixedHeight(18)
        # self.set_img_on_label(self.subinfo_label_img, self.ques_mark)
        # self.subinfo_label_img.setToolTip(
        #     "实验流程：\n1、先选择《基线》进行基线采集（默认120s） \n2、基线采集结束后再选择《反馈》进行反馈(默认5s)")
        #
        # self.hbox_paradigm = QHBoxLayout()
        # self.hbox_paradigm.addWidget(self.paradigm, Qt.AlignLeft)
        # self.hbox_paradigm.addWidget(self.base_checkbox, Qt.AlignLeft)
        # self.hbox_paradigm.addWidget(self.upregulation_checkbox, Qt.AlignLeft)
        # self.hbox_paradigm.addWidget(self.subinfo_label_img, Qt.AlignLeft)
        # self.paramode.addLayout(self.hbox_paradigm, 9)

        # 数据长度
        # self.data_length_label = QLabel("数据长度:")
        # self.data_length_label.setFixedWidth(50)
        # self.data_length = QLineEdit(self.datalen_txt)
        # self.data_length.setFixedWidth(120)
        # self.data_length_label_unit = QLabel("s")
        # self.hbox_datalen = QHBoxLayout()
        # self.hbox_datalen.addWidget(self.data_length_label)
        # self.hbox_datalen.addWidget(self.data_length)
        # self.hbox_datalen.addWidget(self.data_length_label_unit)
        # self.hbox_datalen.setAlignment(Qt.AlignLeft)
        # self.paramode.addLayout(self.hbox_datalen, 9)

        # 反馈长度
        self.data_length_label2 = QLabel("反馈长度:")
        self.data_length_label2.setFixedWidth(50)
        self.data_length2 = QLineEdit(self.datalen_txt)
        self.data_length2.setFixedWidth(120)
        self.data_length_label_unit2 = QLabel("s")
        self.hbox_datalen2 = QHBoxLayout()
        self.hbox_datalen2.addWidget(self.data_length_label2)
        self.hbox_datalen2.addWidget(self.data_length2)
        self.hbox_datalen2.addWidget(self.data_length_label_unit2)
        self.hbox_datalen2.setAlignment(Qt.AlignLeft)
        self.paramode.addLayout(self.hbox_datalen2, 10)

        param_container = QWidget()
        param_container.setLayout(self.paramode)
        # grid.addWidget(param_container, 4, 0)
        grid2.addWidget(param_container, 1, 0)

        # 在布局中插入空白的QWidget来设置间距
        spacer1 = QWidget()
        spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        # grid.addWidget(spacer1, 5, 0)
        grid2.addWidget(spacer1, 2, 0)

        #服务器配置
        self.Hostmode = QVBoxLayout()
        self.Host_Config = QLabel("[ 服务器配置 ]")
        self.hbox_host = QHBoxLayout()
        self.hbox_host.addWidget(self.Host_Config)
        self.hbox_host.addSpacing(110)  # 设置间距大小
        self.hbox_host.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_host, 0)

        # Host
        self.FTP_ip = QLabel("IP:")
        self.FTP_ip.setFixedWidth(50)
        self.FTP_ip_txt = QLineEdit("192.168.1.50")
        self.FTP_ip_txt.setFixedWidth(120)
        self.hbox_ip = QHBoxLayout()
        self.hbox_ip.addWidget(self.FTP_ip)
        self.hbox_ip.addWidget(self.FTP_ip_txt)
        self.subinfo_label_img = QLabel()
        self.subinfo_label_img.setFixedWidth(18)
        self.subinfo_label_img.setFixedHeight(18)
        self.set_img_on_label(self.subinfo_label_img, self.ques_mark)
        self.subinfo_label_img.setToolTip(
            "IP：计算服务器ip地址")
        self.hbox_ip.addWidget(self.subinfo_label_img)
        self.hbox_ip.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_ip, 1)

        #FTP
        self.FTP_Config = QLabel("[ FTP ]")
        self.hbox_ftpc = QHBoxLayout()
        self.hbox_ftpc.addWidget(self.FTP_Config)
        self.hbox_ftpc.addSpacing(155)  # 设置间距大小
        self.subinfo_label_img = QLabel()
        self.subinfo_label_img.setFixedWidth(18)
        self.subinfo_label_img.setFixedHeight(18)
        self.set_img_on_label(self.subinfo_label_img, self.ques_mark)
        self.subinfo_label_img.setToolTip(
            "Port：计算服务器FTP端口。默认为2121 \nUsername：计算服务器FTP用户名。默认为demo \nPassword：计算服务器FTP密码。默认为demo")
        self.hbox_ftpc.addWidget(self.subinfo_label_img)
        self.hbox_ftpc.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_ftpc, 2)
        # Port
        self.FTP_port = QLabel("Port:")
        self.FTP_port.setFixedWidth(50)
        self.FTP_port_txt = QLineEdit("2121")
        self.FTP_port_txt.setFixedWidth(120)
        self.hbox_port = QHBoxLayout()
        self.hbox_port.addWidget(self.FTP_port)
        self.hbox_port.addWidget(self.FTP_port_txt)
        self.hbox_port.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_port, 3)
        # Username
        self.FTP_user = QLabel("Username:")
        self.FTP_user.setFixedWidth(50)
        self.FTP_user_txt = QLineEdit("demo")
        self.FTP_user_txt.setFixedWidth(120)
        self.hbox_user = QHBoxLayout()
        self.hbox_user.addWidget(self.FTP_user)
        self.hbox_user.addWidget(self.FTP_user_txt)
        self.hbox_user.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_user, 4)
        # Password
        self.FTP_passwd = QLabel("Password:")
        self.FTP_passwd.setFixedWidth(50)
        self.FTP_passwd_txt = QLineEdit("demo")
        self.FTP_passwd_txt.setFixedWidth(120)
        self.hbox_pwd = QHBoxLayout()
        self.hbox_pwd.addWidget(self.FTP_passwd)
        self.hbox_pwd.addWidget(self.FTP_passwd_txt)
        self.hbox_pwd.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_pwd, 5)

        #WebSocket
        self.WebSocket_Config = QLabel("[ WebSocket ]")
        self.hbox_websocket = QHBoxLayout()
        self.hbox_websocket.addWidget(self.WebSocket_Config)
        self.hbox_websocket.addSpacing(140)  # 设置间距大小
        self.subinfo_label_img = QLabel()
        self.subinfo_label_img.setFixedWidth(18)
        self.subinfo_label_img.setFixedHeight(18)
        self.set_img_on_label(self.subinfo_label_img, self.ques_mark)
        self.subinfo_label_img.setToolTip(
            "Port：计算服务器WebSocket端口。默认为9002")
        self.hbox_websocket.addWidget(self.subinfo_label_img)
        self.hbox_websocket.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_websocket, 6)
        # Port
        self.websocket_port = QLabel("Port:")
        self.websocket_port.setFixedWidth(50)
        self.websocket_port_txt = QLineEdit("9002")
        self.websocket_port_txt.setFixedWidth(120)
        self.hbox_port2 = QHBoxLayout()
        self.hbox_port2.addWidget(self.websocket_port)
        self.hbox_port2.addWidget(self.websocket_port_txt)
        self.hbox_port2.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_port2, 7)
        # Light
        self.FTP_conn = QLabel("连接状态:")
        self.FTP_conn.setFixedWidth(50)
        self.FTP_conn_light = QFrame(self)
        self.FTP_conn_light.setFixedSize(10, 10)
        self.FTP_conn_light.setStyleSheet(
            "QFrame { background-color: red; border: 1px solid black; border-radius: 5%; }")
        self.FTP_conn_text = QLabel("未连接")
        self.FTP_conn_text.setFixedWidth(40)
        self.FTP_conn_button = QPushButton('连接')
        self.FTP_conn_button.clicked.connect(self.connect_web)  # 连接信号到槽函数
        self.hbox_conn = QHBoxLayout()
        self.hbox_conn.addWidget(self.FTP_conn)
        self.hbox_conn.addWidget(self.FTP_conn_light)
        self.hbox_conn.addWidget(self.FTP_conn_text)
        self.hbox_conn.addWidget(self.FTP_conn_button)
        self.hbox_conn.setAlignment(Qt.AlignLeft)
        self.Hostmode.addLayout(self.hbox_conn, 8)

        ftp_container = QWidget()
        ftp_container.setLayout(self.Hostmode)
        # grid.addWidget(ftp_container, 6, 0)
        grid2.addWidget(ftp_container, 3, 0)

        #app 信息：图标+版本
        image_label = QLabel(self)
        pixmap = QPixmap(os.path.join(self.conf_dir, "webrain1.png"))  # 加载图片
        # 缩放图像以适应标签大小
        scaled_pixmap = pixmap.scaled(450, 220, Qt.AspectRatioMode.KeepAspectRatio)
        image_label.setPixmap(scaled_pixmap)  # 设置图片到label上
        image_label.setAlignment(Qt.AlignCenter)  # 图片居中对齐

        grid3.addWidget(image_label)
        # 创建一个QLabel用于显示文字
        text_label1 = QLabel('WeBrain NeuroCut v1.1', self)
        text_label1.setAlignment(Qt.AlignCenter)  # 第一个文本居中对齐
        font = QFont("Arial", 20)  # 创建字体对象，设置字体和字号
        text_label1.setFont(font)  # 设置第一个标签的字体
        text_label1.setStyleSheet("color: #87CEFA")  # 设置第一个标签的字体颜色为蓝色
        text_label2 = QLabel('University of Electronic Science and Technology of China', self)
        text_label2.setAlignment(Qt.AlignCenter)  # 第二个文本居中对齐
        font = QFont("Arial", 10)  # 创建字体对象，设置字体和字号
        text_label2.setFont(font)  # 设置第一个标签的字体
        grid3.addWidget(text_label1, 1, 0)
        grid3.addWidget(text_label2, 2, 0)

        grid1.addLayout(grid2)
        grid1.addLayout(grid3)

        grid.addLayout(grid1, 4, 0)
        # 在布局中插入空白的QWidget来设置间距
        spacer1 = QWidget()
        spacer1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        grid.addWidget(spacer1, 5, 0)
        #上右侧日志容器
        right_layout = QVBoxLayout()
        self.log_title = QLabel(" - - - - - - - - - 日志信息 - - - - - - - - - ")
        self.hbox_log = QHBoxLayout()
        self.hbox_log.addStretch()
        self.hbox_log.addWidget(self.log_title)
        self.hbox_log.addStretch()
        right_layout.addLayout(self.hbox_log, 0)

        self.console_txt = QTextEdit()
        # 设置字体大小为14
        font = QFont("Arial", 8)
        self.console_txt.setFont(font)
        self.console_txt.setReadOnly(True)  # 设置为只读，这样用户不能编辑它
        right_layout.addWidget(self.console_txt)  # 把文本框添加到布局中，参数根据需要进行调整

        # 左侧参数容器放入上层容器
        func_layout.addLayout(grid, stretch=2)
        # 右侧日志容器放入上层容器
        func_layout.addLayout(right_layout, stretch=1)

        main_layout.addLayout(func_layout)

        # 运行

        self.run_btn = QPushButton("运行")
        self.run_btn.setFixedWidth(80)
        self.run_btn.clicked.connect(self.run)
        self.end_btn = QPushButton("结束")
        self.end_btn.setFixedWidth(80)
        self.end_btn.clicked.connect(self.end)
        # self.help_btn = QPushButton("帮助")
        # self.help_btn.setFixedWidth(80)
        # self.help_btn.clicked.connect(self.help)

        self.hbox_run = QHBoxLayout()

        self.hbox_run.addSpacing(250)  # 添加间距
        self.hbox_run.addWidget(self.run_btn)
        self.hbox_run.addSpacing(200)  # 添加间距
        self.hbox_run.addWidget(self.end_btn)
        self.hbox_run.addSpacing(250)  # 添加间距
        # self.hbox15.addWidget(self.help_btn)
        # self.hbox15.addSpacing(80)  # 添加间距
        main_layout.addLayout(self.hbox_run)

        # 将当前的QWidget嵌入到QMainWindow中
        self.main_window = QMainWindow()
        self.main_window.setCentralWidget(self)

        # 创建运行操作x-special/nautilus-clipboard
        # copy
        # file:///home/oxo/Projects/feedback/code/%E5%AE%A2%E6%88%B7%E7%AB%AF/my_wb_feedback(20240718%E5%A4%87%E4%BB%BD)
        run_action = QAction('开始', self)
        run_action.setStatusTip('开始采集')
        run_action.triggered.connect(self.run)

        # 创建结束操作
        stop_action = QAction('结束', self)
        stop_action.setStatusTip('结束采集')
        stop_action.triggered.connect(self.end)

        # 创建帮助操作及子菜单项
        help_menu = QMenu('&Help', self)
        doc_action = QAction('NeuroCut 帮助文档', self)
        doc_action.triggered.connect(self.help)

        website_action1 = QAction('WeBrain 网站', self)
        website_action1.triggered.connect(self.help_web1)
        # website_action2 = QAction('NIT 网站', self)
        # website_action2.triggered.connect(self.help_web2)

        help_menu.addAction(doc_action)
        help_menu.addAction(website_action1)
        # help_menu.addAction(website_action2)

        help_action = QAction('帮助', self)
        help_action.setMenu(help_menu)

        # 创建退出动作
        exit_bar_action = QAction("退出", self)
        exit_bar_action.setStatusTip('退出 NeuroCut')
        # 连接动作的 triggered 信号到 self.help 方法
        exit_bar_action.triggered.connect(self.closeEvent)

        # 在QMainWindow中添加工具栏和动作
        tool_bar = self.main_window.addToolBar("工具栏")
        tool_bar.setMovable(False)  # 禁止工具栏移动
        tool_bar.addAction(run_action)
        tool_bar.addAction(stop_action)
        tool_bar.addAction(help_action)
        tool_bar.addAction(exit_bar_action)

        # 在QMainWindow中添加状态栏
        self.status_bar = self.main_window.statusBar()
        # 在状态栏上显示初始消息
        self.status_bar.showMessage("欢迎来到NeuroCut ！")
        # 设置窗口显示的内容是最外层容器
        self.setLayout(main_layout)

        # TODO: Add WeBrain Logo
        # self.setWindowIcon(QIcon(os.path.join(os.getcwd(), './bitbug_favicon.ico')))
        self.main_window.setWindowTitle("NeuroCut-v1.0")
        self.main_window.setWindowIcon(QIcon(os.path.join(self.conf_dir, "webrain2.ico")))
        self.main_window.show()

    def select_vhdr(self):
        vhdr_path = QFileDialog.getOpenFileName(
            self, "Open file", "/", "VHDR Files (*.vhdr);;EDF Files (*.EDF)"
        )
        self.vhdr_path = vhdr_path[0]
        self.data_txt.setText(vhdr_path[0])
        file_ext = os.path.splitext(vhdr_path[0])[1]  #扩展名

        if file_ext == ".vhdr":
            self.chanloc_path = self.chanloc_bp
        elif file_ext == ".EDF":
            self.chanloc_path = self.chanloc_edf
        else:
            self.chanloc_path = ''

    def select_save_dir(self):
        save_path = QFileDialog.getExistingDirectory(self, "Open Dir", "/")
        self.save_path = save_path
        self.save_txt.setText(save_path)

    def select_channel(self):
        channel_path = QFileDialog.getOpenFileName(
            self, "Open file", "/", "Mat Files (*.mat)"
        )
        self.chanloc_path = channel_path[0]
        self.channel_txt.setText(channel_path[0])

    def set_img_on_label(self, lb, img_b64):
        img_b64decode = base64.b64decode(img_b64)
        img = QImage.fromData(img_b64decode)
        pix = QPixmap.fromImage(img.scaled(18, 18))
        lb.setPixmap(pix)

    # def set_img_on_label(self, lb, img_b64):
    #     img_b64decode = base64.b64decode(img_b64)
    #     img_io = io.BytesIO(img_b64decode)
    #     img = Image.open(img_io)
    #     pix = img.toqpixmap()
    #     lb.setScaledContents(True)  # 自适应QLabel大小
    #     lb.setPixmap(pix)

    def select_item(self, item):
        if item == "默认配置文件":
            self.power_checkbox.setVisible(False)
            self.network_checkbox.setVisible(False)
            self.ini_params()
            #self.config_path = os.path.join(os.getcwd(), "./conf/fb_params.conf")
        elif item == "选择计算模式":
            self.power_checkbox.setVisible(True)
            self.network_checkbox.setVisible(True)
        elif item == "修改配置文件":
            self.power_checkbox.setVisible(False)
            self.network_checkbox.setVisible(False)
            # import subprocess
            # subprocess.call(["code", "--new-window", self.config_path])
            os.startfile(self.config_path)
        elif item == "导入配置文件":
            self.power_checkbox.setVisible(False)
            self.network_checkbox.setVisible(False)
            self.select_config()
        else:
            self.power_checkbox.setVisible(False)
            self.network_checkbox.setVisible(False)

    def select_config(self):
        config_path = QFileDialog.getOpenFileName(
            self, "Open file", "/", "Conf Files (*.conf)"
        )
        self.config_path = config_path[0]

    def change_curr_algo(self):
        config = {}
        if os.path.exists(self.config_path):
            with open(self.config_path, "r") as f:
                lines = f.read()
                config = json.loads(lines)

        config["current_algo"] = self.calc_mode
        with open(self.config_path, "w") as f:
            json.dump(config, f, indent=4)

    def change_calc_mode(self):
        if self.power_checkbox.isChecked():
            self.calc_mode = "fb_EEG_Power"
        else:
            self.calc_mode = "fb_EEG_network"

        self.change_curr_algo()

    def change_age(self):
        config = {}
        if os.path.exists(self.config_path):
            with open(self.config_path, "r") as f:
                lines = f.read()
                config = json.loads(lines)

        config[self.calc_mode]["age"] = self.sub_age_txt.text()
        # config["fb_EEG_Power"]["age"] = self.sub_age_txt
        with open(self.config_path, "w") as f:
            json.dump(config, f, indent=4)

    def ini_params(self):
        config = {}
        if os.path.exists(self.config_ini_path):
            with open(self.config_ini_path, "r") as f:
                lines = f.read()
                config = json.loads(lines)
        with open(self.config_path, "w") as f:
            json.dump(config, f, indent=4)

    def change_gender(self):
        if self.male_checkbox.isChecked():
            self.gender = "male"
        else:
            self.gender = "female"

    def change_paradigm(self):
        if self.base_checkbox.isChecked():
            self.baseflag = "1"
            self.datalen_txt = "120"
        else:
            self.baseflag = "0"
            self.datalen_txt = "5"
        self.data_length.setText(self.datalen_txt)
        config = {}
        if os.path.exists(self.config_path):
            with open(self.config_path, "r") as f:
                lines = f.read()
                config = json.loads(lines)

        config[self.calc_mode]["baseflag"] = self.baseflag
        # config["fb_EEG_Power"]["age"] = self.sub_age_txt
        with open(self.config_path, "w") as f:
            json.dump(config, f, indent=4)

    def connect_web(self):
        print("正在连接webSocket")
        format_url = 'ws://192.168.0.105:9002/websocket/data'
        print(format_url)
        request_url = QUrl(format_url)
        self.webSocket.open(request_url)

    def websocketConnect(self):
        print("websocketConnect")
        self

    def webSocketDisconnect(self):
        print("disconnected")

    def webSocketMessageReceived(self, p_str):
        print("webSocketMessageReceived"+p_str)

    def run(self):
        if self.test_thread is None or not self.test_thread.is_alive():
            self.vmrk_max_len = 11
            self.vmrk_start_len = self.vmrk_max_len
            self.data_length_txt = self.data_length.text()

            #  print 输出都会被重定向到 self.console_txt 上
            self.redirect_text = RedirectText()
            self.redirect_text.write_signal.connect(self.update_console_text)

            # TODO: checkout all the input, ensure all the input is valid
            try:

                # TODO: Add New Slide Function
                self.bp_record = BP_Recorder(
                    self.vhdr_path,
                    self.save_path,
                    int(self.data_length_txt),
                    self.vmrk_max_len,
                    self.chanloc_path,
                    self.config_path,
                    self.FTP_host_txt.text(),
                    int(self.FTP_port_txt.text()),
                    self.FTP_user_txt.text(),
                    self.FTP_passwd_txt.text(),
                    self.sub_id_txt.text(),
                    self.sub_name_txt.text(),
                    self.sub_age_txt.text(),
                    self.gender,
                    self.redirect_text,
                )
                # self.start_test(self.bp_record)
                sys.stdout = self.bp_record.redirect_text
                if self.baseflag == "1":
                    self.test_thread = threading.Thread(target=self.bp_record.slide_base)
                else:
                    self.test_thread = threading.Thread(target=self.bp_record.slide_vhdr)
                self.test_thread.start()

                pass
            except KeyboardInterrupt:
                print("==========slide结束==========")
            self.status_bar.showMessage("状态 ： 程序正在运行 ......")
        else:
            print("程序正在运行！")

    def end(self):
        if self.test_thread is not None and self.test_thread.is_alive():
            self.bp_record.should_stop.set()
            self.test_thread.join()
            sys.stdout = sys.__stdout__
            self.status_bar.clearMessage()
        else:
            self.status_bar.clearMessage()
            print("程序结束运行")

    def help_web1(self):
        webbrowser.open('https://webrain.uestc.edu.cn/')

    def help_web2(self):
        webbrowser.open('http://www.neuro.uestc.edu.cn/NIT.html')

    def help(self):
        os.startfile(self.help_path)
        # subprocess.run(['start', '', self.help_path])

    #更新日志信息
    def update_console_text(self, text):
        cursor = self.console_txt.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.console_txt.setTextCursor(cursor)
        self.console_txt.ensureCursorVisible()

    #退出程序
    def closeEvent(self, event):
        self.end()
        # 结束应用程序
        QCoreApplication.quit()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    w = MainUi()
    sys.exit(app.exec_())
